home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / daemons / timed / slave.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-12-23  |  13.9 KB  |  557 lines

  1. /*
  2.  * Copyright (c) 1985 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that this notice is preserved and that due credit is given
  7.  * to the University of California at Berkeley. The name of the University
  8.  * may not be used to endorse or promote products derived from this
  9.  * software without specific prior written permission. This software
  10.  * is provided ``as is'' without express or implied warranty.
  11.  */
  12.  
  13. #ifndef lint
  14. static char sccsid[] = "@(#)slave.c    2.17 (Berkeley) 12/23/87";
  15. #endif /* not lint */
  16.  
  17. #include "globals.h"
  18. #include <protocols/timed.h>
  19. #include <setjmp.h>
  20.  
  21. extern jmp_buf jmpenv;
  22.  
  23. extern u_short sequence;
  24.  
  25. slave()
  26. {
  27.     int length;
  28.     int senddateack;
  29.     long electiontime, refusetime, looktime;
  30.     u_short seq;
  31.     char candidate[MAXHOSTNAMELEN];
  32.     struct tsp *msg, to, *readmsg();
  33.     struct sockaddr_in saveaddr, msaveaddr;
  34.     struct timeval wait;
  35.     struct timeval time, otime;
  36.     struct tsp *answer, *acksend();
  37.     int timeout();
  38.     char *date();
  39.     long casual();
  40.     int bytenetorder();
  41.     char olddate[32];
  42.     struct sockaddr_in server;
  43.     register struct netinfo *ntp;
  44.     int ind;
  45.     struct tsp resp;
  46.     extern int Mflag;
  47.     extern int justquit;
  48. #ifdef MEASURE
  49.     extern FILE *fp;
  50. #endif
  51.     if (slavenet) {
  52.         resp.tsp_type = TSP_SLAVEUP;
  53.         resp.tsp_vers = TSPVERSION;
  54.         (void)strcpy(resp.tsp_name, hostname);
  55.         bytenetorder(&resp);
  56.         if (sendto(sock, (char *)&resp, sizeof(struct tsp), 0,
  57.             &slavenet->dest_addr, sizeof(struct sockaddr_in)) < 0) {
  58.             syslog(LOG_ERR, "sendto: %m");
  59.             exit(1);
  60.         }
  61.     }
  62.  
  63.     if (status & MASTER) {
  64. #ifdef MEASURE
  65.         if (fp == NULL) {
  66.             fp = fopen("/usr/adm/timed.masterlog", "w");
  67.             setlinebuf(fp);
  68.         }
  69. #endif
  70.         syslog(LOG_INFO, "THIS MACHINE IS A SUBMASTER");
  71.         if (trace) {
  72.             fprintf(fd, "THIS MACHINE IS A SUBMASTER\n");
  73.         }
  74.         for (ntp = nettab; ntp != NULL; ntp = ntp->next)
  75.             if (ntp->status == MASTER)
  76.                 masterup(ntp);
  77.  
  78.     } else {
  79.         syslog(LOG_INFO, "THIS MACHINE IS A SLAVE");
  80.         if (trace) {
  81.             fprintf(fd, "THIS MACHINE IS A SLAVE\n");
  82.         }
  83.     }
  84.  
  85.     seq = 0;
  86.     senddateack = OFF;
  87.     refusetime = 0;
  88.  
  89.     (void)gettimeofday(&time, (struct timezone *)0);
  90.     electiontime = time.tv_sec + delay2;
  91.     if (Mflag)
  92.         if (justquit)
  93.             looktime = time.tv_sec + delay2;
  94.         else 
  95.             looktime = 1;
  96.     else
  97.         looktime = 0;
  98.  
  99. loop:
  100.     length = sizeof(struct sockaddr_in);
  101.     (void)gettimeofday(&time, (struct timezone *)0);
  102.     if (time.tv_sec > electiontime) {
  103.         if (trace) 
  104.             fprintf(fd, "election timer expired\n");
  105.         longjmp(jmpenv, 1);
  106.     }
  107.     if (looktime && time.tv_sec > looktime) {
  108.         if (trace) 
  109.             fprintf(fd, "Looking for nets to master and loops\n");
  110.         
  111.         if (nignorednets > 0) {
  112.             for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
  113.                 if (ntp->status == IGNORE) {
  114.                     lookformaster(ntp);
  115.                     if (ntp->status == MASTER)
  116.                         masterup(ntp);
  117.                     else
  118.                         ntp->status = IGNORE;
  119.                 }
  120.             }
  121.             setstatus();
  122. #ifdef MEASURE
  123.             /*
  124.              * Check to see if we just became master
  125.              * (file not open)
  126.              */
  127.             if (fp == NULL) {
  128.                 fp = fopen("/usr/adm/timed.masterlog", "w");
  129.                 setlinebuf(fp);
  130.             }
  131. #endif
  132.         }
  133.  
  134.         for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
  135.             if (ntp->status == MASTER) {
  136.             to.tsp_type = TSP_LOOP;
  137.             to.tsp_vers = TSPVERSION;
  138.             to.tsp_seq = sequence++;
  139.             to.tsp_hopcnt = 10;
  140.             (void)strcpy(to.tsp_name, hostname);
  141.             bytenetorder(&to);
  142.             if (sendto(sock, (char *)&to, sizeof(struct tsp), 0,
  143.                 &ntp->dest_addr, sizeof(struct sockaddr_in)) < 0) {
  144.                 syslog(LOG_ERR, "sendto: %m");
  145.                 exit(1);
  146.             }
  147.             }
  148.         }
  149.         (void)gettimeofday(&time, (struct timezone *)0);
  150.         looktime = time.tv_sec + delay2;
  151.     }
  152.     wait.tv_sec = electiontime - time.tv_sec + 10;
  153.     wait.tv_usec = 0;
  154.     msg = readmsg(TSP_ANY, (char *)ANYADDR, &wait, (struct netinfo *)NULL);
  155.     if (msg != NULL) {
  156.         switch (msg->tsp_type) {
  157.         case TSP_SETDATE:
  158. #ifdef TESTING
  159.         case TSP_TEST:
  160. #endif
  161.         case TSP_MSITE:
  162.         case TSP_TRACEOFF:
  163.         case TSP_TRACEON:
  164.             break;
  165.         case TSP_MASTERUP:
  166.             if (fromnet == NULL) {
  167.                 if (trace) {
  168.                     fprintf(fd, "slave ignored: ");
  169.                     print(msg, &from);
  170.                 }
  171.                 goto loop;
  172.             }
  173.             break;
  174.         default:
  175.             if (fromnet == NULL || fromnet->status == IGNORE) {
  176.                 if (trace) {
  177.                     fprintf(fd, "slave ignored: ");
  178.                     print(msg, &from);
  179.                 }
  180.                 goto loop;
  181.             }
  182.             break;
  183.         }
  184.  
  185.         switch (msg->tsp_type) {
  186.  
  187.         case TSP_ADJTIME:
  188.             if (fromnet->status != SLAVE)
  189.                 break;
  190.             (void)gettimeofday(&time, (struct timezone *)0);
  191.             electiontime = time.tv_sec + delay2;
  192.             if (seq != msg->tsp_seq) {
  193.                 seq = msg->tsp_seq;
  194.                 if ((status & SUBMASTER) == SUBMASTER) {
  195.                     synch((msg->tsp_time.tv_sec * 1000) + 
  196.                         (msg->tsp_time.tv_usec / 1000));
  197.                 } else {
  198.                     adjclock(&(msg->tsp_time));
  199.                 }
  200.             }
  201.             break;
  202.         case TSP_SETTIME:
  203.             if (fromnet->status != SLAVE)
  204.                 break;
  205.             if (seq == msg->tsp_seq)
  206.                 break;
  207.  
  208.             seq = msg->tsp_seq;
  209.  
  210.             (void)strcpy(olddate, date());
  211.             (void)gettimeofday(&otime, (struct timezone *)0);
  212.             (void)settimeofday(&msg->tsp_time,
  213.                 (struct timezone *)0);
  214.             syslog(LOG_NOTICE, "date changed by %s from: %s",
  215.                 msg->tsp_name, olddate);
  216.             logwtmp(otime, msg->tsp_time);
  217.             if ((status & SUBMASTER) == SUBMASTER)
  218.                 spreadtime();
  219.             (void)gettimeofday(&time, (struct timezone *)0);
  220.             electiontime = time.tv_sec + delay2;
  221.  
  222.             if (senddateack == ON) {
  223.                 senddateack = OFF;
  224.                 msg->tsp_type = TSP_DATEACK;
  225.                 (void)strcpy(msg->tsp_name, hostname);
  226.                 bytenetorder(msg);
  227.                 length = sizeof(struct sockaddr_in);
  228.                 if (sendto(sock, (char *)msg, 
  229.                         sizeof(struct tsp), 0,
  230.                         &saveaddr, length) < 0) {
  231.                     syslog(LOG_ERR, "sendto: %m");
  232.                     exit(1);
  233.                 }
  234.             }
  235.             break;
  236.         case TSP_MASTERUP:
  237.             if (slavenet && fromnet != slavenet)
  238.                 break;
  239.             makeslave(fromnet);
  240.             setstatus();
  241.             msg->tsp_type = TSP_SLAVEUP;
  242.             msg->tsp_vers = TSPVERSION;
  243.             (void)strcpy(msg->tsp_name, hostname);
  244.             bytenetorder(msg);
  245.             answerdelay();
  246.             length = sizeof(struct sockaddr_in);
  247.             if (sendto(sock, (char *)msg, sizeof(struct tsp), 0, 
  248.                         &from, length) < 0) {
  249.                 syslog(LOG_ERR, "sendto: %m");
  250.                 exit(1);
  251.             }
  252.             backoff = 1;
  253.             delay2 = casual((long)MINTOUT, (long)MAXTOUT);
  254.             (void)gettimeofday(&time, (struct timezone *)0);
  255.             electiontime = time.tv_sec + delay2;
  256.             refusetime = 0;
  257.             break;
  258.         case TSP_MASTERREQ:
  259.             if (fromnet->status != SLAVE)
  260.                 break;
  261.             (void)gettimeofday(&time, (struct timezone *)0);
  262.             electiontime = time.tv_sec + delay2;
  263.             break;
  264.         case TSP_SETDATE:
  265.             saveaddr = from;
  266.             msg->tsp_type = TSP_SETDATEREQ;
  267.             msg->tsp_vers = TSPVERSION;
  268.             (void)strcpy(msg->tsp_name, hostname);
  269.             for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
  270.                 if (ntp->status == SLAVE)
  271.                     break;
  272.             }
  273.             if (ntp == NULL)
  274.                 break;
  275.             answer = acksend(msg, &ntp->dest_addr, (char *)ANYADDR,
  276.                 TSP_DATEACK, ntp);
  277.             if (answer != NULL) {
  278.                 msg->tsp_type = TSP_ACK;
  279.                 bytenetorder(msg);
  280.                 length = sizeof(struct sockaddr_in);
  281.                 if (sendto(sock, (char *)msg,
  282.                     sizeof(struct tsp), 0, &saveaddr,
  283.                     length) < 0) {
  284.                     syslog(LOG_ERR, "sendto: %m");
  285.                     exit(1);
  286.                 }
  287.                 senddateack = ON;
  288.             }
  289.             break;
  290.         case TSP_SETDATEREQ:
  291.             saveaddr = from;
  292.             if (status != SUBMASTER || fromnet->status != MASTER)
  293.                 break;
  294.             for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
  295.                 if (ntp->status == SLAVE)
  296.                     break;
  297.             }
  298.             ind = findhost(msg->tsp_name);
  299.             if (ind < 0) {
  300.                 syslog(LOG_WARNING,
  301.                 "DATEREQ from uncontrolled machine");
  302.                 break;
  303.             }
  304.             syslog(LOG_DEBUG,
  305.                 "forwarding date change request for %s",
  306.                 msg->tsp_name);
  307.             (void)strcpy(msg->tsp_name, hostname);
  308.             answer = acksend(msg, &ntp->dest_addr, (char *)ANYADDR,
  309.                 TSP_DATEACK, ntp);
  310.             if (answer != NULL) {
  311.                 msg->tsp_type = TSP_DATEACK;
  312.                 bytenetorder(msg);
  313.                 length = sizeof(struct sockaddr_in);
  314.                 if (sendto(sock, (char *)msg,
  315.                     sizeof(struct tsp), 0, &saveaddr,
  316.                     length) < 0) {
  317.                     syslog(LOG_ERR, "sendto: %m");
  318.                     exit(1);
  319.                 }
  320.             }
  321.             break;
  322.         case TSP_TRACEON:
  323.             if (!(trace)) {
  324.                 fd = fopen(tracefile, "w");
  325.                 setlinebuf(fd);
  326.                 fprintf(fd, "Tracing started on: %s\n\n", 
  327.                                 date());
  328.             }
  329.             trace = ON;
  330.             break;
  331.         case TSP_TRACEOFF:
  332.             if (trace) {
  333.                 fprintf(fd, "Tracing ended on: %s\n", date());
  334.                 (void)fclose(fd);
  335.             }
  336. #ifdef GPROF
  337.             moncontrol(0);
  338.             _mcleanup();
  339.             moncontrol(1);
  340. #endif
  341.             trace = OFF;
  342.             break;
  343.         case TSP_SLAVEUP:
  344.             if ((status & MASTER) && fromnet->status == MASTER) {
  345.                 ind = addmach(msg->tsp_name, &from);
  346.                 newslave(ind, msg->tsp_seq);
  347.             }
  348.             break;
  349.         case TSP_ELECTION:
  350.             if (fromnet->status == SLAVE) {
  351.                 (void)gettimeofday(&time, (struct timezone *)0);
  352.                 electiontime = time.tv_sec + delay2;
  353.                 seq = 0;            /* reset sequence number */
  354.                 if (time.tv_sec < refusetime)
  355.                     msg->tsp_type = TSP_REFUSE;
  356.                 else {
  357.                     msg->tsp_type = TSP_ACCEPT;
  358.                     refusetime = time.tv_sec + 30;
  359.                 }
  360.                 (void)strcpy(candidate, msg->tsp_name);
  361.                 (void)strcpy(msg->tsp_name, hostname);
  362.                 answerdelay();
  363.                 server = from;
  364.                 answer = acksend(msg, &server, candidate, TSP_ACK,
  365.                     (struct netinfo *)NULL);
  366.                 if (answer == NULL)
  367.                     syslog(LOG_WARNING,
  368.                        "no answer from master candidate\n");
  369.             } else {    /* fromnet->status == MASTER */
  370.                 to.tsp_type = TSP_QUIT;
  371.                 (void)strcpy(to.tsp_name, hostname);
  372.                 server = from;
  373.                 answer = acksend(&to, &server, msg->tsp_name,
  374.                     TSP_ACK, (struct netinfo *)NULL);
  375.                 if (answer == NULL) {
  376.                     syslog(LOG_WARNING,
  377.                         "election error: no reply to QUIT");
  378.                 } else {
  379.                     (void) addmach(msg->tsp_name, &from);
  380.                 }
  381.             }
  382.             break;
  383.                 case TSP_CONFLICT:
  384.             if (fromnet->status != MASTER)
  385.                 break;
  386.                         /*
  387.                          * After a network partition, there can be
  388.                          * more than one master: the first slave to
  389.                          * come up will notify here the situation.
  390.                          */
  391.                         (void)strcpy(to.tsp_name, hostname);
  392.  
  393.                         if (fromnet == NULL)
  394.                                 break;
  395.                         for(;;) {
  396.                                 to.tsp_type = TSP_RESOLVE;
  397.                                 answer = acksend(&to, &fromnet->dest_addr,
  398.                                     (char *)ANYADDR, TSP_MASTERACK, fromnet);
  399.                                 if (answer == NULL)
  400.                                         break;
  401.                                 to.tsp_type = TSP_QUIT;
  402.                                 server = from;
  403.                                 msg = acksend(&to, &server, answer->tsp_name,
  404.                                     TSP_ACK, (struct netinfo *)NULL);
  405.                                 if (msg == NULL) {
  406.                                         syslog(LOG_WARNING,
  407.                         "conflict error: no reply to QUIT");
  408.                 } else {
  409.                                         (void) addmach(answer->tsp_name, &from);
  410.                 }
  411.                         }
  412.                         masterup(fromnet);
  413.                         break;
  414.         case TSP_MSITE:
  415.             if (!slavenet)
  416.                 break;
  417.             msaveaddr = from;
  418.             msg->tsp_type = TSP_MSITEREQ;
  419.             msg->tsp_vers = TSPVERSION;
  420.             (void)strcpy(msg->tsp_name, hostname);
  421.             answer = acksend(msg, &slavenet->dest_addr,
  422.                      (char *)ANYADDR, TSP_ACK, slavenet);
  423.             if (answer != NULL) {
  424.                 msg->tsp_type = TSP_ACK;
  425.                 length = sizeof(struct sockaddr_in);
  426.                 bytenetorder(msg);
  427.                 if (sendto(sock, (char *)msg, 
  428.                         sizeof(struct tsp), 0,
  429.                         &msaveaddr, length) < 0) {
  430.                     syslog(LOG_ERR, "sendto: %m");
  431.                     exit(1);
  432.                 }
  433.             }
  434.             break;
  435.         case TSP_ACCEPT:
  436.         case TSP_REFUSE:
  437.             break;
  438.         case TSP_RESOLVE:
  439.             break;
  440.         case TSP_QUIT:
  441.             /* become slave */
  442. #ifdef MEASURE
  443.             if (fp != NULL) {
  444.                 (void)fclose(fp);
  445.                 fp = NULL;
  446.             }
  447. #endif
  448.             longjmp(jmpenv, 2);
  449.             break;
  450. #ifdef TESTING
  451.         case TSP_TEST:
  452.             electiontime = 0;
  453.             break;
  454. #endif
  455.         case TSP_MSITEREQ:
  456.             if (status & MASTER)
  457.                 break;
  458.             if (trace) {
  459.                 fprintf(fd, "garbage: ");
  460.                 print(msg, &from);
  461.             }
  462.             break;
  463.  
  464.         case TSP_LOOP:
  465.             /* looking for loops of masters */
  466.             if ( !(status & MASTER))
  467.                 break;
  468.             if (fromnet->status == SLAVE) {
  469.                 if ( !strcmp(msg->tsp_name, hostname)) {
  470.                   for(;;) {
  471.                     to.tsp_type = TSP_RESOLVE;
  472.                     answer = acksend(&to, &fromnet->dest_addr,
  473.                     (char *)ANYADDR, TSP_MASTERACK,
  474.                     fromnet);
  475.                     if (answer == NULL)
  476.                         break;
  477.                     to.tsp_type = TSP_QUIT;
  478.                     (void)strcpy(to.tsp_name, hostname);
  479.                     server = from;
  480.                     answer = acksend(&to, &server,
  481.                     answer->tsp_name, TSP_ACK,
  482.                     (struct netinfo *)NULL);
  483.                     if (answer == NULL) {
  484.                     syslog(LOG_ERR, "loop kill error");
  485.                     } else {
  486.                     electiontime = 0;
  487.                     }
  488.                   }
  489.                 } else {
  490.                 if (msg->tsp_hopcnt-- <= 0)
  491.                     break;
  492.                 bytenetorder(msg);
  493.                 ntp = nettab;
  494.                 for (; ntp != NULL; ntp = ntp->next)
  495.                     if (ntp->status == MASTER)
  496.                     if (sendto(sock, (char *)msg, 
  497.                         sizeof(struct tsp), 0,
  498.                         &ntp->dest_addr, length) < 0) {
  499.                         syslog(LOG_ERR, "sendto: %m");
  500.                         exit(1);
  501.                     }
  502.                 }
  503.             } else {
  504.                 /*
  505.                  * We should not have received this from a net
  506.                  * we are master on.  There must be two masters
  507.                  * in this case.
  508.                  */
  509.                 if (fromnet->my_addr.s_addr == from.sin_addr.s_addr)
  510.                 break;
  511.                 for (;;) {
  512.                 to.tsp_type = TSP_RESOLVE;
  513.                 answer = acksend(&to, &fromnet->dest_addr,
  514.                     (char *)ANYADDR, TSP_MASTERACK,
  515.                     fromnet);
  516.                 if (answer == NULL)
  517.                     break;
  518.                 to.tsp_type = TSP_QUIT;
  519.                 (void)strcpy(to.tsp_name, hostname);
  520.                 server = from;
  521.                 answer = acksend(&to, &server, answer->tsp_name,
  522.                     TSP_ACK, (struct netinfo *)NULL);
  523.                 if (answer == NULL) {
  524.                     syslog(LOG_ERR, "loop kill error2");
  525.                 } else {
  526.                     (void)addmach(msg->tsp_name, &from);
  527.                 }
  528.                 }
  529.             }
  530.             break;
  531.         default:
  532.             if (trace) {
  533.                 fprintf(fd, "garbage: ");
  534.                 print(msg, &from);
  535.             }
  536.             break;
  537.         }
  538.     }
  539.     goto loop;
  540. }
  541.  
  542. /*
  543.  * Used before answering a broadcast message to avoid network
  544.  * contention and likely collisions.
  545.  */
  546. answerdelay()
  547. {
  548.     struct timeval timeout;
  549.  
  550.     timeout.tv_sec = 0;
  551.     timeout.tv_usec = delay1;
  552.  
  553.     (void)select(0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL,
  554.         &timeout);
  555.     return;
  556. }
  557.